package cn.cosmosx.base.filter;

import cn.cosmosx.base.helper.CurrentThreadContextHelper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

/**
 * httpRequest请求体包装处理过滤器
 */
@Slf4j
@Component
public class HttpServletRequestWrapperFilter extends OncePerRequestFilter {
    // 请求类型：form表单提交的无需处理
    private final static String[] UN_WRAPPER_LIST = {"multipart/form-data"};

    @Override
    protected void doFilterInternal(@NotNull HttpServletRequest request,
                                    @NotNull HttpServletResponse response,
                                    @NotNull FilterChain filterChain) throws ServletException, IOException {
        // 无请求类型或form表单提交的无需处理
        if (request.getContentType() == null
                || Arrays.stream(UN_WRAPPER_LIST).anyMatch(t -> request.getContentType().contains(t))) {
            // 将请求数据缓存到本地线程
            CurrentThreadContextHelper.init(request, response);
            filterChain.doFilter(request, response);
            return;
        }
        // 将请求数据wrap一层，如果前端请求数据是解密的，此处可以进行解密操作
        RequestBodyWrapper wrapper = new RequestBodyWrapper(request);
        // todo 解密、验签请求体数据
        // 将请求数据缓存到本地线程
        CurrentThreadContextHelper.init(wrapper, response);
        filterChain.doFilter(wrapper, response);
    }

    public static class RequestBodyWrapper extends HttpServletRequestWrapper {
        // 用于保存读取body中数据
        private byte[] bodyBuff;
        // body中数据转为JSON格式
        private JSONObject jsonData;
        // 请求头信息
        private Map<String, String> headers;

        public RequestBodyWrapper(HttpServletRequest request) throws IOException {
            super(request);
            // 处理请求头数据
            setHeaders(request);
            // 处理请求体数据
            BufferedReader reader = request.getReader();
            StringBuilder builder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                builder.append(line);
            }
            setBodyBuff(builder.toString().getBytes());
            reader.close();
        }

        public void setHeaders(HttpServletRequest request) {
            headers = new LinkedHashMap<>();
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String headerKey = headerNames.nextElement();
                String headerValue = request.getHeader(headerKey);
                headers.put(headerKey.toLowerCase(), headerValue);
            }
        }

        @Override
        public String getHeader(String headerKey) {
            if (headers.isEmpty()) {
                return super.getHeader(headerKey);
            }
            return headers.get(StringUtils.lowerCase(headerKey));
        }

        public Map<String, String> getHeaders() {
            return headers;
        }

        public void setBodyBuff(byte[] bodyBuff) {
            this.bodyBuff = bodyBuff;
            try {
                this.jsonData = JSON.parseObject(new String(bodyBuff));
                log.info("HTTP REQUEST BODY: {}", jsonData);
            } catch (Exception e) {
                log.warn("http request data json parse error", e);
            }
        }

        public byte[] getBodyBuff() {
            return this.bodyBuff;
        }

        @Override
        public Enumeration<String> getParameterNames() {
            if (jsonData != null) {
                return Collections.enumeration(jsonData.keySet());
            }
            return super.getParameterNames();
        }

        @Override
        public String getParameter(String name) {
            if (jsonData != null) {
                return jsonData.getString(name);
            }
            return super.getParameter(name);
        }

        public JSONObject getParamsJSONObject() {
            return jsonData;
        }

        /**
         * 获取请求参数转换为的实体对象
         * @param type - 实体对象类型
         * @return - bean
         */
        public <T> T getParamEntity(Class<T> type) {
            return fromJSON(type);
        }

        private <T> T fromJSON(Class<T> clazz) {
            return new Gson().fromJson(jsonData.toJSONString(), TypeToken.of(clazz).getType());
        }

        public Map<String, Object> getParamsMap() {
            if (jsonData != null) {
                return jsonData.getInnerMap();
            }
            return null;
        }

        @Override
        public BufferedReader getReader() {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }

        /**
         * HttpServletRequest二进制数据请求体
         */
        @Override
        public ServletInputStream getInputStream() {
            final ByteArrayInputStream stream = new ByteArrayInputStream(bodyBuff);
            return new ServletInputStream() {
                @Override
                public int read() {
                    return stream.read();
                }

                @Override
                public boolean isFinished() {
                    return false;
                }

                @Override
                public boolean isReady() {
                    return false;
                }

                @Override
                public void setReadListener(ReadListener listener) {
                }
            };
        }
    }
}
